package com.weijianhuawen.wjblog.common.aspect;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.weijianhuawen.wjblog.common.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @version: java version 8
 * @Author: weijianhuawen
 * @description: 日志切面
 * @date: 2024-10-15 0:44
 */
@Aspect
@Component
@Slf4j
public class ApiOperationLogAspect {
    // 目标为添加自定义日志朱注解@ApiOperationLog的方法
    @Pointcut("@annotation(com.weijianhuawen.wjblog.common.aspect.ApiOperationLog)")
    public void apiOperationLog() {}


    @Around("apiOperationLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try {
            // 请求开始时间
            long startTime = System.currentTimeMillis();

            //MDC 日志诊断
            MDC.put("traceId", UUID.randomUUID().toString());

            //获取请求的类与方法
            String className = proceedingJoinPoint.getTarget().getClass().getSimpleName();
            String methodName = proceedingJoinPoint.getSignature().getName();

            //请求入参
            Object[] args = proceedingJoinPoint.getArgs();
            //转换为json字符串
            String argsJsonString = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(","));

            //功能描述信息
            String description = getApiOperationLogDescription(proceedingJoinPoint);

            //打印相关请求参数
            log.info("===== 请求开始：[{}], 入参：{}，请求类：{}，请求方法：{} =====",
                        description, argsJsonString, className, methodName);

            //执行切点方法
            Object result = proceedingJoinPoint.proceed();

            //执行耗时
            long endTime = System.currentTimeMillis();
            long runningTime = endTime - startTime;

            //输出相关信息
            log.info("===== 请求结束：[{}]，运行用时：{}ms， 返回值： {} =====",
                        description, runningTime, JsonUtil.toJsonString(result));

            return result;

        } finally {
            MDC.clear();
        }

    }

    /**
     * 获取注解描述信息
     * @param proceedingJoinPoint 切点
     * @return 描述信息
     */
    private String getApiOperationLogDescription(ProceedingJoinPoint proceedingJoinPoint){
        // 获取目标方法相关参数
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        //获取方法体
        Method method = signature.getMethod();

        //获取方法的注解
        ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);

        //返回注解中的描述信息
        return apiOperationLog.description();
    }

    /**
     * 转换为json字符串
     * @return
     */
    private Function<Object, String> toJsonStr() {
        return arg -> JsonUtil.toJsonString(arg);
    }
}
